package com.uinnova.product.eam.web.asset.peer;

import com.binary.core.util.BinaryUtils;
import com.binary.jdbc.Page;
import com.uinnova.product.eam.comm.bean.CcCiAttrDefConfVO;
import com.uinnova.product.eam.comm.bean.CcCiClassInfoConfVO;
import com.uinnova.product.eam.comm.model.es.AssetDetailAttrConf;
import com.uinnova.product.eam.comm.model.es.AssetListAttrConf;
import com.uinnova.product.eam.service.ICISwitchSvc;
import com.uinnova.product.eam.service.IEamCIClassApiSvc;
import com.uinnova.product.eam.service.asset.AssetContent;
import com.uinnova.product.eam.service.asset.AssetDetailAttrConfSvc;
import com.uinnova.product.eam.service.asset.AssetListAttrConfSvc;
import com.uinnova.product.eam.web.asset.bean.AssetDetailAttrConfVO;
import com.uinnova.product.eam.web.asset.bean.AssetLisConfSearchParam;
import com.uinnova.product.eam.web.asset.bean.AssetListAttrConfVO;
import com.uinnova.product.vmdb.comm.model.ci.CcCiAttrDef;
import com.uinnova.product.vmdb.provider.ci.bean.CcCiClassInfo;
import com.uino.bean.cmdb.base.ESCIClassInfo;
import com.uino.bean.cmdb.base.ESCIInfo;
import com.uino.bean.cmdb.base.LibType;
import com.uino.bean.permission.base.SysUser;
import com.uino.dao.cmdb.ESCIClassSvc;
import com.uino.util.sys.BeanUtil;
import com.uino.util.sys.SysUtil;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.Operator;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.index.search.MatchQuery;
import org.elasticsearch.search.sort.SortBuilder;
import org.elasticsearch.search.sort.SortBuilders;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;

/**
 * @author zdh_c
 */
@Service
public class AssetConfigPeer implements AssetContent {

    @Resource
    AssetListAttrConfSvc listAttrConfSvc;

    @Resource
    AssetDetailAttrConfSvc detailAttrConfSvc;

    @Autowired
    ICISwitchSvc ciSwitchSvc;

    @Resource
    IEamCIClassApiSvc ciClassApiSvc;

    @Autowired
    private ESCIClassSvc classSvc;


    public Long saveOrUpdateListAttr(AssetListAttrConfVO listAttrVO) {
        AssetListAttrConf attrConf = new AssetListAttrConf();
        BeanUtil.copyProperties(listAttrVO, attrConf);
        return listAttrConfSvc.saveOrUpdate(attrConf);
    }

    public AssetListAttrConfVO getListAttr(Long appSquareConfId, Integer type) {
        AssetListAttrConf attrConf = listAttrConfSvc.getListAttr(appSquareConfId, type);
        if (BinaryUtils.isEmpty(attrConf)) {
            return null;
        }
        AssetListAttrConfVO target = new AssetListAttrConfVO();
        BeanUtil.copyProperties(attrConf, target);
        return target;
    }

    public CcCiClassInfoConfVO getListAttrClassInfo(Long appSquareConfId, Integer type) {
        return listAttrConfSvc.getListShowAttrList(appSquareConfId,type);
    }

    public Integer deleteListAttrById(Long id) {
        return listAttrConfSvc.deleteListAttrById(id);
    }


    public Long saveOrUpdateDetailAttr(AssetDetailAttrConfVO detailAttrConfVO) {
        AssetDetailAttrConf target = new AssetDetailAttrConf();
        BeanUtil.copyProperties(detailAttrConfVO, target);
        Long num = detailAttrConfSvc.saveOrUpdateDetailAttr(target);
        return num;
    }

    public AssetDetailAttrConfVO getDetailAttr(Long appSquareConfId) {
        AssetDetailAttrConf conf = detailAttrConfSvc.getDetailAttr(appSquareConfId);
        AssetDetailAttrConfVO target = new AssetDetailAttrConfVO();
        if (BinaryUtils.isEmpty(conf)) {
            return target;
        }
        BeanUtil.copyProperties(conf, target);
        return target;
    }

    public Integer deleteDetailAttrById(Long id) {
        return detailAttrConfSvc.deleteDetailAttrById(id);
    }


    public CcCiClassInfoConfVO getClassInfoDetailAttr(Long appSquareConfId) {
        return detailAttrConfSvc.getClassInfoDetailAttr(appSquareConfId);
    }

    public Page<ESCIInfo> queryCiInfoPage(LibType libType, AssetLisConfSearchParam param) {
        CcCiClassInfoConfVO attrClassInfo = getListAttrClassInfo(param.getAppSquareConfId(), param.getType());
        BoolQueryBuilder query = QueryBuilders.boolQuery();
        SysUser currentUserInfo = SysUtil.getCurrentUserInfo();
        if (LibType.PRIVATE.equals(libType)) {
            query.must(QueryBuilders.termQuery("ownerCode.keyword", currentUserInfo.getLoginCode()));
        }
        if (!BinaryUtils.isEmpty(attrClassInfo)) {
            query.must(QueryBuilders.termQuery("classId", attrClassInfo.getCiClass().getId()));
            if (!BinaryUtils.isEmpty(param.getWord())) {

                Map<Long, String> defMap = getSourceDefMapByWordLabelAndClassId(attrClassInfo.getCiClass().getId());
                List<String> proNames = new ArrayList<>();
                List<CcCiAttrDef> showListCIAttrInfo = attrClassInfo.getShowListCIAttrInfo();
                List<CcCiAttrDefConfVO> tagListCIAttrInfo = attrClassInfo.getTagListCIAttrInfo();

                for (CcCiAttrDef ccCiAttrDef : showListCIAttrInfo) {
                    if (defMap.containsKey(ccCiAttrDef.getId())) {
                        proNames.add("attrs." + defMap.get(ccCiAttrDef.getId()));
                    }
                }
                for (CcCiAttrDef ccCiAttrDef : tagListCIAttrInfo) {
                    if (defMap.containsKey(ccCiAttrDef.getId())) {
                        proNames.add("attrs." + defMap.get(ccCiAttrDef.getId()));
                    }
                }

                String[] fieldNames = proNames.toArray(new String[proNames.size()]);
                query.must(QueryBuilders.multiMatchQuery(param.getWord(), fieldNames).operator(Operator.AND).type(MatchQuery.Type.PHRASE_PREFIX).lenient(true));
            }
        } else if (param.getType().equals(0)) {
            // 表单未配置查询全部字段
            CcCiClassInfo classInfo = ciClassApiSvc.queryClassAndAttrMappingByCode(param.getClassCode());
            if (!BinaryUtils.isEmpty(param.getWord())) {
                query.must(QueryBuilders.multiMatchQuery(param.getWord(), "attrs.*").operator(Operator.AND).type(MatchQuery.Type.PHRASE_PREFIX).lenient(true));
            }
            query.must(QueryBuilders.termQuery("classId", classInfo.getCiClass().getId()));
        } else {
            // 返回空数据
            Page<ESCIInfo> page = new Page<>();
            page.setData(Collections.emptyList());
            return page;
        }

        List<SortBuilder<?>> sorts = new ArrayList<>();
//        sorts.add(SortBuilders.fieldSort("attrs.资产状态.keyword").order(SortOrder.DESC));
        sorts.add(SortBuilders.fieldSort("modifyTime").order(SortOrder.DESC));
        boolean isHighLight = param.getType().equals(0) ? false : true;
        List<ESCIInfo> allCi = new ArrayList<>();
        Page<ESCIInfo> page = ciSwitchSvc.getESCIInfoPageByQuery(currentUserInfo.getDomainId(), 1 ,3000, query, sorts, isHighLight, libType);
        allCi.addAll(page.getData());
        if (page.getTotalRows() > 3000) {
            for (int i = 2; i < Math.ceil(page.getTotalRows() * 1.0 / 3000); i++) {
                Page<ESCIInfo> pageByQuery = ciSwitchSvc.getESCIInfoPageByQuery(currentUserInfo.getDomainId(), i, 3000, query, sorts, isHighLight, libType);
                if (CollectionUtils.isEmpty(pageByQuery.getData())) {
                    break;
                }
                allCi.addAll(pageByQuery.getData());
            }
        }
        Iterator<ESCIInfo> iterator = allCi.iterator();
      List<ESCIInfo> cancellationCiList = new ArrayList<>();
        while (iterator.hasNext()) {
            ESCIInfo next = iterator.next();
            if (!BinaryUtils.isEmpty(next) && CANCELLED.equals(next.getAttrs().get(RELEASE_STATE))) {
                cancellationCiList.add(next);
                iterator.remove();
            }
        }
        allCi.addAll(cancellationCiList);
        List<ESCIInfo> data = allCi.stream().skip((param.getPageNum() - 1) * param.getPageSize()).limit(param.getPageSize()).
                collect(Collectors.toList());
        Page<ESCIInfo> result = new Page<>();
        result.setPageNum(param.getPageNum());
        result.setPageSize(param.getPageSize());
        result.setData(data);
        result.setTotalRows(allCi.size());
        result.setTotalPages((int)Math.ceil(allCi.size() * 1.0 / param.getPageSize()));
        return result;
    }

    private Map<Long, String> getSourceDefMapByWordLabelAndClassId(Long classId) {
        Map<Long, String> defMap = new ConcurrentHashMap<>();
        Long domainId = SysUtil.getCurrentUserInfo().getDomainId();
        List<ESCIClassInfo> ciClassInfos = classSvc.getTargetAttrDefsByClassIds(domainId, Arrays.asList(classId));
        if (!CollectionUtils.isEmpty(ciClassInfos)) {
            for (ESCIClassInfo cls : ciClassInfos) {
                cls.getCcAttrDefs().forEach(def -> {
                    defMap.put(def.getId(), def.getProStdName());
                });
            }
        }
        return defMap;
    }
}
